﻿using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.InteropServices;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Interop;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
using Xceed.Wpf.Toolkit;

namespace CPPEI.Coolzon.UI
{
    /// <summary>
    /// ColorSlider.xaml 的交互逻辑
    /// </summary>
    public partial class ColorSlider : UserControl
    {
        [DllImport("gdi32")]
        private static extern int GetPixel(IntPtr hDc, int nXPos, int nYPos);
        [DllImport("user32")]
        public static extern IntPtr GetWindowDC(IntPtr hWnd);
        [DllImport("user32")]
        private static extern int ReleaseDC(IntPtr hWnd, IntPtr hDC);

        private double dbDistance;
        private Hashtable gsCol = new Hashtable();
        private const double RECTWIDTH = 10;
        private Rectangle _selectRect;
        private Rectangle selectRect
        {
            get
            {
                return _selectRect;
            }
            set
            {
                if (_selectRect != null)
                {
                    _selectRect.StrokeThickness = 0;
                }
                _selectRect = value;
                if (value != null)
                {
                    value.StrokeThickness = 2;
                    colorCanvas.SelectedColor = (value.Tag as GradientStop).Color;
                }
            }
        }

        private enum Gradient
        {
            LineGradient,
            RadiaGradient
        }

        private Gradient gradient = Gradient.LineGradient;
        private Color GradientColor
        {
            get
            {
                return (Color)GetValue(GradientColorProperty);
            }
            set
            {
                SetValue(GradientColorProperty, value);
            }
        }
        public static readonly DependencyProperty GradientColorProperty
            = DependencyProperty.Register("GradientBrush", typeof(Color), typeof(ColorSlider), new PropertyMetadata(GradientColorPropertyChangedCallback));

        public Brush SelectedBrush
        {
            get
            {
                return colorGradient.Background;
            }
        }

        public ColorSlider()
        {
            InitializeComponent();

            this.SetBinding(GradientColorProperty, new Binding("SelectedColor") { ElementName = "colorCanvas", Mode = BindingMode.TwoWay });

            colorGradient.MouseLeftButtonUp += colorGradient_MouseLeftButtonUp;

            //this.Loaded += ColorSlider_Loaded;
        }

        public void DelectRect()
        {
            if (selectRect != null)
            {
                if (colorGradient.Background is LinearGradientBrush)
                {
                    LinearGradientBrush lgb = colorGradient.Background as LinearGradientBrush;
                    lgb.GradientStops.Remove((GradientStop)gsCol[selectRect]);
                }
                else if (colorGradient.Background is RadialGradientBrush)
                {
                    RadialGradientBrush rgb = colorGradient.Background as RadialGradientBrush;
                    rgb.GradientStops.Remove((GradientStop)gsCol[selectRect]);
                }
                gsCol.Remove(selectRect);
                colorGradient.Children.Remove(selectRect);
            }
        }

        void ColorSlider_KeyDown(object sender, KeyEventArgs e)
        {
            if (e.Key == Key.Delete)
            {
                if (selectRect != null)
                {
                    gsCol.Remove(selectRect);
                    colorGradient.Children.Remove(selectRect);
                }
            }
        }

        void colorGradient_MouseLeftButtonUp(object sender, MouseButtonEventArgs e)
        {
            Point point = e.GetPosition(colorGradient);
            double offset = ConvertLeftToOffset(point.X - RECTWIDTH / 2);
            Rectangle rect = GenerateRect(point.X, GetColor(), offset);
            rect.Stroke = new SolidColorBrush(Colors.Black);
            rect.StrokeThickness = 2;

            if (colorGradient.Background is LinearGradientBrush)
            {
                LinearGradientBrush lgb = colorGradient.Background as LinearGradientBrush;
                lgb.GradientStops.Add((GradientStop)gsCol[rect]);
            }
            else if (colorGradient.Background is RadialGradientBrush)
            {
                RadialGradientBrush rgb = colorGradient.Background as RadialGradientBrush;
                rgb.GradientStops.Add((GradientStop)gsCol[rect]);
            }

            selectRect = rect;
        }
        public void InitColorGradient(Brush brush = null)
        {
            gsCol.Clear();
            colorGradient.Children.Clear();
            if (brush is LinearGradientBrush || brush is RadialGradientBrush)
            {
                GradientBrush tmpBrush = brush as GradientBrush;
                foreach (var stop in tmpBrush.GradientStops)
                {
                    double left = 0;
                    Dispatcher.BeginInvoke(System.Windows.Threading.DispatcherPriority.Render,
                        new Action(() =>
                        {
                            left = ConvertOffsetToLeft(stop.Offset);
                            if(left > colorGradient.ActualWidth - RECTWIDTH)
                            {
                                left = colorGradient.ActualWidth - RECTWIDTH;
                            }
                            GenerateRect(left, stop.Color, stop.Offset);
                            ChangeLineGradient();
                        }));
                }
            }
            else
            {
                Rectangle rect = GenerateRect(0, (Color)ColorConverter.ConvertFromString("#FFB91E1E"), 0);
                selectRect = rect;

                GenerateRect(colorGradient.Width - RECTWIDTH, (Color)ColorConverter.ConvertFromString("#FFF7F3F3"), 1);
                //默认线性
                ChangeLineGradient();
            }
        }

        public static void GradientColorPropertyChangedCallback(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            ColorSlider colorSlider = d as ColorSlider;
            if (colorSlider.selectRect != null)
            {
                GradientStop gs = colorSlider.gsCol[colorSlider.selectRect] as GradientStop;
                if (gs != null)
                {
                    gs.Color = (Color)e.NewValue;
                }
            }
        }


        private Rectangle GenerateRect(double left, Color color, double offset)
        {
            Rectangle rect = new Rectangle();
            rect.Width = RECTWIDTH;
            rect.Height = colorGradient.Height;
            rect.Fill = new SolidColorBrush(Colors.Gray);
            rect.Stroke = new SolidColorBrush(Colors.Black);
            Canvas.SetLeft(rect, left);

            colorGradient.Children.Add(rect);

            rect.MouseMove += rect_MouseMove;
            rect.MouseUp += rect_MouseUp;
            rect.MouseLeftButtonDown += rect_MouseLeftButtonDown;

            GradientStop gs = new GradientStop() { Color = color, Offset = offset };

            rect.Tag = gs;

            gsCol.Add(rect, gs);

            return rect;
        }

        void rect_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
        {
            Point point = e.GetPosition(colorGradient);
            Rectangle rect = sender as Rectangle;
            double rectLeft = Canvas.GetLeft(rect);
            dbDistance = point.X - rectLeft;
            rect.Stroke = new SolidColorBrush(Colors.Black);
            rect.StrokeThickness = 2;
            rect.CaptureMouse();

            selectRect = rect;
        }

        void rect_MouseUp(object sender, MouseButtonEventArgs e)
        {
            e.Handled = true;
            Rectangle rect = sender as Rectangle;
            rect.ReleaseMouseCapture();
        }

        void rect_MouseMove(object sender, MouseEventArgs e)
        {
            if (e.LeftButton == MouseButtonState.Pressed)
            {
                Point point = e.GetPosition(colorGradient);
                Rectangle rect = sender as Rectangle;
                if (point.X - dbDistance <= 0 || point.X - dbDistance + RECTWIDTH >= colorGradient.ActualWidth) return;
                Canvas.SetLeft(rect, point.X - dbDistance);

                double offset = ConvertLeftToOffset(Canvas.GetLeft(rect));

                GradientStop gs = gsCol[rect] as GradientStop;
                gs.Offset = offset;
            }
        }

        private double ConvertLeftToOffset(double left)
        {
            return left / colorGradient.ActualWidth;
        }

        private double ConvertOffsetToLeft(double offset)
        {
            return offset * colorGradient.ActualWidth;
        }

        private void ChangeLineGradient()
        {
            if (gradient == Gradient.LineGradient)
            {
                LinearGradientBrush lgb = new LinearGradientBrush();
                lgb.StartPoint = new Point(0, 0.5);
                lgb.EndPoint = new Point(1, 0.5);
                foreach (DictionaryEntry gs in gsCol)
                {
                    lgb.GradientStops.Add((GradientStop)gs.Value);
                }
                colorGradient.Background = lgb;

                tbStartPointX.SetBinding(TextBox.TextProperty, new Binding("StartPoint.X") { Source = lgb, Mode = BindingMode.TwoWay });
                tbStartPointY.SetBinding(TextBox.TextProperty, new Binding("StartPoint.Y") { Source = lgb, Mode = BindingMode.TwoWay });
                tbEndPointX.SetBinding(TextBox.TextProperty, new Binding("EndPoint.X") { Source = lgb, Mode = BindingMode.TwoWay });
                tbEndPointY.SetBinding(TextBox.TextProperty, new Binding("EndPoint.Y") { Source = lgb, Mode = BindingMode.TwoWay });
                tbOpacity.SetBinding(TextBox.TextProperty, new Binding("Opacity") { Source = lgb, Mode = BindingMode.TwoWay });

                canvasGradientLine.Background = lgb;
            }
            else if (gradient == Gradient.RadiaGradient)
            {
                RadialGradientBrush rgb = new RadialGradientBrush();
                foreach (DictionaryEntry gs in gsCol)
                {
                    rgb.GradientStops.Add((GradientStop)gs.Value);
                }
                colorGradient.Background = rgb;

                tbRCenterX.SetBinding(TextBox.TextProperty, new Binding("Center.X") { Source = rgb, Mode = BindingMode.TwoWay });
                tbRCenterY.SetBinding(TextBox.TextProperty, new Binding("Center.Y") { Source = rgb, Mode = BindingMode.TwoWay });
                tbRadiusX.SetBinding(TextBox.TextProperty, new Binding("RadiusX") { Source = rgb, Mode = BindingMode.TwoWay });
                tbRadiusY.SetBinding(TextBox.TextProperty, new Binding("RadiusY") { Source = rgb, Mode = BindingMode.TwoWay });
                tbROpacity.SetBinding(TextBox.TextProperty, new Binding("Opacity") { Source = rgb, Mode = BindingMode.TwoWay });
                tbOriginX.SetBinding(TextBox.TextProperty, new Binding("GradientOrigin.X") { Source = rgb, Mode = BindingMode.TwoWay });
                tbOriginY.SetBinding(TextBox.TextProperty, new Binding("GradientOrigin.Y") { Source = rgb, Mode = BindingMode.TwoWay });

                canvasGradientRadia.Background = rgb;
            }
        }

        private Color GetColor()
        {
            Point point = PointToScreen(Mouse.GetPosition(this));
            WindowInteropHelper wi = new WindowInteropHelper(Application.Current.MainWindow);
            IntPtr hDC = GetWindowDC(IntPtr.Zero);
            int intColor = GetPixel(hDC, (int)point.X, (int)point.Y);
            ReleaseDC(IntPtr.Zero, hDC);
            byte b = (byte)((intColor >> 0x10) & 0xffL);
            byte g = (byte)((intColor >> 8) & 0xffL);
            byte r = (byte)(intColor & 0xffL);
            return Color.FromRgb(r, g, b);
        }

        private void btnLine_Click(object sender, RoutedEventArgs e)
        {
            gradient = Gradient.LineGradient;
            gdGradientLine.Visibility = Visibility.Visible;
            gdRadiaLine.Visibility = Visibility.Collapsed;

            InitColorGradient();
        }

        private void btnRadia_Click(object sender, RoutedEventArgs e)
        {
            gradient = Gradient.RadiaGradient;
            gdGradientLine.Visibility = Visibility.Collapsed;
            gdRadiaLine.Visibility = Visibility.Visible;

            InitColorGradient();
        }
    }
}
